home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / tde3.zip / TDECFG.C < prev    next >
C/C++ Source or Header  |  1993-06-05  |  23KB  |  747 lines

  1. /*
  2.  * A configuration utility was written to customize the tde executable file.
  3.  * You only need one file to run tde - the executable.  No configuration files
  4.  * to worry about.
  5.  *
  6.  * With this version, there is no need to figure the offsets each time
  7.  * tde.exe is modified.  The original program to find the offsets was written
  8.  * by Jim Lee, jlee@ece.orst.edu.  Simple pattern matching machines are used
  9.  * to find the offsets.  On one pass thru tde.exe, the machines will quickly
  10.  * find all signatures.  The pattern matching machines are loosely based on
  11.  * the multiple string search algorithm by Alfred Aho and Margaret Corasick.
  12.  *
  13.  * See:
  14.  *
  15.  *   Alfred V. Aho and Margaret J. Corasick, "Efficient String Matching:
  16.  *    An Aid to Bibliographic Search."  _Communications of the ACM_ 18
  17.  *    (No. 6): 333-340, 1975.
  18.  *
  19.  *
  20.  * Program name:  tdecfg
  21.  * Author:        Frank Davis
  22.  * Date:          October 5, 1991
  23.  * Date:          June 5, 1993
  24.  *
  25.  * This program is released into the public domain.  You may distribute
  26.  * it freely, Frank Davis.
  27.  */
  28.  
  29.  
  30. #include <bios.h>
  31. #include <dos.h>
  32. #include <io.h>
  33. #include <malloc.h>
  34. #include <stdlib.h>
  35. #include <stdio.h>
  36. #include <string.h>
  37.  
  38. #include "tdecfg.h"
  39.  
  40.  
  41. struct vcfg cfg;                /* video stuff */
  42. FILE *tde_exe;                  /* FILE pointer to tde.exe */
  43.  
  44. long sort_offset;
  45. long mode_offset;
  46. long color_offset;
  47. long macro_offset;
  48. long keys_offset;
  49. long two_key_offset;
  50. long help_offset;
  51.  
  52. struct screen cfg_choice[] = {
  53.    {5,25,"1.  Change colors" },
  54.    {7,25,"2.  Redefine keys" },
  55.    {9,25,"3.  Install new help screen" },
  56.   {11,25,"4.  Set default modes" },
  57.   {13,25,"5.  Install permanent macro file" },
  58.   {15,25,"6.  Read in a configuration file" },
  59.   {17,25,"7.  Exit" },
  60.  {20,20,"Please enter choice: " },
  61.   {0,0,NULL}
  62. };
  63.  
  64.  
  65. char *greatest_composer_ever = "W. A. Mozart, 1756-1791";
  66.  
  67.  
  68. /*
  69.  * Name:    main
  70.  * Date:    October 5, 1991
  71.  * Notes:   Strategy is fairly straight forward -  1) initialize all the
  72.  *          variables  2) show the user a color sample  3) make the changes
  73.  *          permanent if desired.
  74.  */
  75. void main( int argc, char *argv[] )
  76. {
  77. int  rc;
  78. int  c;
  79. char fname[82];
  80. char *buff;
  81.  
  82.    /*
  83.     * lets get a 8k buffer for our pattern matching machines.
  84.     */
  85.    if ((buff = malloc( 8200 )) == NULL) {
  86.       puts( "\nNot enough memory." );
  87.       exit( 1 );
  88.    }
  89.  
  90.    puts( "\nEnter tde executable file name (<Enter> = \"tde.exe\")  :" );
  91.    gets( fname );
  92.  
  93.    if (strlen(fname) == 0)
  94.       strcpy( fname, "tde.exe" );
  95.  
  96.    if ((rc = access( fname, EXIST )) != 0) {
  97.       puts( "\nFile not found." );
  98.       exit( 1 );
  99.    } else if ((tde_exe = fopen( fname, "r+b" )) == NULL ) {
  100.       puts( "\nCannot open executable file." );
  101.       exit( 2 );
  102.    }
  103.    find_offsets( buff );
  104.    free( buff );
  105.  
  106.    video_config( );
  107.    cls( );
  108.    show_box( 0, 0, cfg_choice, NORMAL );
  109.    for (rc=0; rc != 1;) {
  110.       xygoto( 42, 20 );
  111.       c = getkey( );
  112.       while (c != '1' && c != '2' && c != '3' && c != '4' && c != '5' &&
  113.              c != '6' && c != '7')
  114.          c = getkey( );
  115.       switch (c) {
  116.          case '1' :
  117.             tdecolor( );
  118.             show_box( 0, 0, cfg_choice, NORMAL );
  119.             break;
  120.          case '2' :
  121.             tdekeys( );
  122.             show_box( 0, 0, cfg_choice, NORMAL );
  123.             break;
  124.          case '3' :
  125.             tdehelp( );
  126.             show_box( 0, 0, cfg_choice, NORMAL );
  127.             break;
  128.          case '4' :
  129.             tdemodes( );
  130.             show_box( 0, 0, cfg_choice, NORMAL );
  131.             break;
  132.          case '5' :
  133.             tdemacro( );
  134.             show_box( 0, 0, cfg_choice, NORMAL );
  135.             break;
  136.          case '6' :
  137.             tdecfgfile( );
  138.             show_box( 0, 0, cfg_choice, NORMAL );
  139.             break;
  140.          case '7' :
  141.             rc = 1;
  142.             break;
  143.       }
  144.    }
  145.    fcloseall( );
  146.    puts( " " );
  147.    puts( " " );
  148. }
  149.  
  150.  
  151. /***********************  original comments  *************************/
  152. /*
  153. ** OFFSETS.C    -       Automatically scan tde.exe for config offsets
  154. **
  155. ** Author:  Jim Lee (jlee@ece.orst.edu)
  156. **   Date:  5/12/93
  157. ** Status:  Released to the public domain
  158. **
  159. **      This little utility takes the drudgery out of updating tdecfg.h
  160. **      every time you re-compile tde.exe.  Just remove the hard-coded
  161. **      offsets in tdecfg.h and replace them with '#include "newoff.h"'.
  162. **      Then run 'offsets tde.exe > newoff.h'.  Now re-compile tdecfg
  163. **      and you're done!
  164. **
  165. */
  166. /*****************************   end   *******************************/
  167.  
  168. /*
  169.  * Name:    find_offsets
  170.  * Date:    June 5, 1993
  171.  * Notes:   to increase the speed, I "wired" a pattern matching machine
  172.  *           for each of the signatures, Frank.  the states in the machines
  173.  *           correspond to the characters in the sig's.  on one pass through
  174.  *           the file, all 7 signatures will be found.  all signatures are
  175.  *           8 characters long.  it's also a little faster if we read the file
  176.  *           in big chunks.  also note that we never have to back-up or reread
  177.  *           the file.
  178.  */
  179. void find_offsets( char *buff )
  180. {
  181. long off;
  182. int  m1, m2, m3, m4, m5, m6, m7;
  183. char sig1[8] = { '\x00','\x01','\x02','\x03','\x04','\x05','\x06','\x07' };
  184. char sig2[8] = "$ modes";
  185. char sig3[8] = "$colors";
  186. char sig4[8] = "$macbuf";
  187. char sig5[8] = "$  keys";
  188. char sig6[8] = "$twokey";
  189. char sig7[8] = "$  help";
  190. unsigned int cnt;
  191. register char *b;
  192.  
  193.    /*
  194.     * Let's start the machines 100k into the executable.
  195.     */
  196.    m1 = m2 = m3 = m4 = m5 = m6 = m7 = 0;
  197.    off = 100000L;
  198.    fseek( tde_exe, off, SEEK_SET );
  199.    while (!feof( tde_exe )) {
  200.       cnt = fread( buff, sizeof(char), 8192, tde_exe );
  201.       b = (char *)buff;
  202.       for (; cnt > 0; off++, cnt--, b++) {
  203.          if (m1 < 8) {
  204.             m1 =  sig1[m1] == *b ? m1+1 : 0;
  205.             if (m1 == 8)
  206.                sort_offset = off - 7L;
  207.          }
  208.          if (m2 < 8) {
  209.             m2 =  sig2[m2] == *b ? m2+1 : 0;
  210.             if (m2 == 8)
  211.                mode_offset = off - 7L;
  212.          }
  213.          if (m3 < 8) {
  214.             m3 =  sig3[m3] == *b ? m3+1 : 0;
  215.             if (m3 == 8)
  216.                color_offset = off - 7L;
  217.          }
  218.          if (m4 < 8) {
  219.             m4 =  sig4[m4] == *b ? m4+1 : 0;
  220.             if (m4 == 8)
  221.                macro_offset = off - 7L;
  222.          }
  223.          if (m5 < 8) {
  224.             m5 =  sig5[m5] == *b ? m5+1 : 0;
  225.             if (m5 == 8)
  226.                keys_offset = off - 7L;
  227.          }
  228.          if (m6 < 8) {
  229.             m6 =  sig6[m6] == *b ? m6+1 : 0;
  230.             if (m6 == 8)
  231.                two_key_offset = off - 7L;
  232.          }
  233.          if (m7 < 8) {
  234.             m7 =  sig7[m7] == *b ? m7+1 : 0;
  235.             if (m7 == 8)
  236.                help_offset = off - 7L;
  237.          }
  238.       }
  239.    }
  240. }
  241.  
  242.  
  243. /*
  244.  * Name:    xygoto
  245.  * Date:    July 21, 1991
  246.  * Notes:   Use the video interrupt to set the cursor.
  247.  */
  248. void xygoto( int col, int row )
  249. {
  250. union REGS inregs, outregs;
  251.  
  252.    inregs.h.ah = 2;
  253.    inregs.h.bh = 0;
  254.    inregs.h.dh = row;
  255.    inregs.h.dl = col;
  256.    int86( VIDEO_INT, &inregs, &outregs );
  257. }
  258.  
  259.  
  260. /*
  261.  * Name:    video_config
  262.  * Date:    July 21, 1991
  263.  * Notes:   See main.c for more info.
  264.  */
  265. void video_config( void )
  266. {
  267. #pragma pack( 1 )    /* Use pragma to force packing on byte boundaries. */
  268.  
  269. struct LOWMEMVID
  270. {
  271.    char     vidmode;           /* 0x449 */
  272.    unsigned scrwid;            /* 0x44A */
  273.    unsigned scrlen;            /* 0x44C */
  274.    unsigned scroff;            /* 0x44E */
  275.    struct   LOCATE
  276.    {
  277.       unsigned char col;
  278.       unsigned char row;
  279.    } csrpos[8];                /* 0x450 */
  280.    struct   CURSIZE
  281.    {
  282.       unsigned char end;
  283.       unsigned char start;
  284.    } csrsize;                  /* 0x460 */
  285.    char      page;             /* 0x462 */
  286.    unsigned  addr_6845;        /* 0x463 */
  287.    char      crt_mode_set;     /* 0x465 */
  288.    char      crt_palette;      /* 0x466 */
  289.    char      system_stuff[29]; /* 0x467 */
  290.    char      rows;             /* 0x484 */
  291.    unsigned  points;           /* 0x485 */
  292.    char      ega_info;         /* 0x487 */
  293.    char      info_3;           /* 0x488 */
  294. } vid;
  295. struct LOWMEMVID _far *pvid = &vid;
  296.  
  297. #pragma pack( )    /* revert to previously defined pack pragma. */
  298.  
  299. union REGS in, out;
  300. unsigned char temp, active_display;
  301.  
  302.    /* Move system information into uninitialized structure variable. */
  303.    movedata( 0, 0x449, FP_SEG( pvid ), FP_OFF( pvid ), sizeof( vid ) );
  304.  
  305.    cfg.rescan = FALSE;
  306.    in.x.ax =  0x1a00;
  307.    int86( VIDEO_INT, &in, &out );
  308.    temp = out.h.al;
  309.    active_display = out.h.bl;
  310.    if (temp == 0x1a && (active_display == 7 || active_display == 8))
  311.       cfg.adapter = VGA;
  312.    else {
  313.       in.h.ah =  0x12;
  314.       in.h.bl =  0x10;
  315.       int86( VIDEO_INT, &in, &out );
  316.       if (out.h.bl != 0x10) {         /* EGA */
  317.          if (vid.ega_info & 0x08) {
  318.             if (vid.addr_6845 == 0x3d4)
  319.                cfg.adapter = CGA;
  320.             else
  321.                cfg.adapter = MDA;
  322.          } else
  323.             cfg.adapter = EGA;
  324.       } else if (vid.addr_6845 == 0x3d4)
  325.          cfg.adapter = CGA;
  326.       else
  327.          cfg.adapter = MDA;
  328.    }
  329.  
  330.    if (cfg.adapter == CGA)
  331.       cfg.rescan = TRUE;
  332.  
  333.    cfg.mode = vid.vidmode;
  334.    if (vid.addr_6845 == 0x3D4) {
  335.       cfg.color = TRUE;
  336.       FP_SEG( cfg.videomem ) = 0xb800;
  337.    } else {
  338.       cfg.color = FALSE;
  339.       FP_SEG( cfg.videomem ) = 0xb000;
  340.    }
  341.    FP_OFF( cfg.videomem ) = 0x0000;
  342.    if (cfg.color == TRUE)
  343.       cfg.attr = COLOR_ATTR;
  344.    else
  345.       cfg.attr = MONO_ATTR;
  346.  
  347.    cfg.overscan = vid.crt_palette;
  348. }
  349.  
  350.  
  351. /*
  352.  * Name:    getkey
  353.  * Date:    July 21, 1991
  354.  * Notes:   Waits for keyboard input and returns the key pressed by the user.
  355.  */
  356. int getkey( void )
  357. {
  358. unsigned key;
  359. unsigned lo;
  360.  
  361.    /*
  362.     *  _bios_keybrd == int 16.  It returns the scan code in ah, hi part of key,
  363.     *  and the ascii key code in al, lo part of key.
  364.     */
  365.    key = _bios_keybrd( 0 );
  366.    lo = key & 0X00FF;
  367.    lo = (int)((lo == 0) ? (((key & 0XFF00) >> 8) + 256) : lo);
  368.    return( lo );
  369. }
  370.  
  371.  
  372. /*
  373.  * Name:    s_output
  374.  * Date:    July 21, 1991
  375.  * Passed:  s:     the string to display
  376.  *          line:  line number to begin display
  377.  *          col:   column number to begin display
  378.  *          attr:  color to display string
  379.  * Notes:   See tdeasm.c for more info
  380.  */
  381. void s_output( char far *s, int line, int col, int attr )
  382. {
  383. int far *screen_ptr;
  384. int max_col;
  385. int off;
  386.  
  387.    max_col = 80;
  388.    screen_ptr = cfg.videomem;
  389.    off = line * 160 + col * 2;
  390.  
  391.    ASSEMBLE {
  392.         push    ds              /* MUST save ds */
  393.         push    di              /* save di on stack */
  394.         push    si              /* save si on stack */
  395.  
  396.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  397.         mov     cx, WORD PTR col                /* put cols in cx */
  398.         mov     dx, WORD PTR max_col            /* keep max_col in dx */
  399.         mov     di, WORD PTR screen_ptr         /* load offset of screen ptr */
  400.         add     di, WORD PTR off
  401.         mov     ax, WORD PTR screen_ptr+2       /* load segment of screen ptr */
  402.         mov     es, ax
  403.         mov     si, WORD PTR s  /* load offset of string ptr */
  404.         or      si, si          /* is it == NULL? */
  405.         je      getout          /* yes, no output needed */
  406.         mov     ax, WORD PTR s+2        /* load segment of string ptr */
  407.         or      ax, ax          /* is pointer == NULL? */
  408.         je      getout          /* yes, no output needed */
  409.         mov     ds, ax          /* load segment of text in ds */
  410.         mov     ah, bl          /* put attribute in AH */
  411.    }
  412. top:
  413.  
  414.    ASSEMBLE {
  415.         cmp     cx, dx          /* col < max_cols? */
  416.         jge     getout          /* no, thru with line */
  417.         lodsb                   /* get next char in string - put in al */
  418.         or      al, al          /* is it '\0' */
  419.         je      getout          /* yes, end of string */
  420.         stosw                   /* else show attr + char on screen (ah + al) */
  421.         inc     cx              /* col++ */
  422.         jmp     SHORT top       /* get another character */
  423.    }
  424. getout:
  425.  
  426.    ASSEMBLE {
  427.         pop     si              /* get back si */
  428.         pop     di              /* get back di */
  429.         pop     ds              /* get back ds */
  430.    }
  431. }
  432.  
  433.  
  434. /*
  435.  * Name:    hlight_line
  436.  * Date:    July 21, 1991
  437.  * Passed:  x:     column to begin hi lite
  438.  *          y:     line to begin hi lite
  439.  *          lgth:  number of characters to hi lite
  440.  *          attr:  attribute color
  441.  * Notes:   The attribute byte is the hi byte.
  442.  */
  443. void hlight_line( int x, int y, int lgth, int attr )
  444. {
  445. int off, far *pointer;
  446.  
  447.    pointer = cfg.videomem;
  448.    off = y * 160 + 2 * x + 1;  /* add one - so it points to attribute byte */
  449.    ASSEMBLE {
  450.         push    di              /* save es */
  451.  
  452.         mov     cx, lgth        /* number of characters to change color */
  453.  
  454.         mov     di, WORD PTR pointer    /* get destination - video memory */
  455.         add     di, off                 /* add offset */
  456.         mov     ax, WORD PTR pointer+2
  457.         mov     es, ax
  458.         mov     ax, attr        /* attribute */
  459.    }
  460. lite_len:
  461.  
  462.    ASSEMBLE {
  463.         stosb                   /* store a BYTE */
  464.         inc     di              /* skip over character to next attribute */
  465.         loop    lite_len        /* change next attribute */
  466.         pop     di              /* restore di */
  467.    }
  468. }
  469.  
  470.  
  471. /*
  472.  * Name:    scroll_window
  473.  * Date:    October 5, 1991
  474.  * Passed:  lines:  number of lines to scroll
  475.  *          r1:     row scroll starts on
  476.  *          c1:     column scroll start on
  477.  *          r2:     ending row of scroll
  478.  *          c2:     ending column of scroll
  479.  *          attr:   color of scroll
  480.  * Notes:   Clear a window using color.  Use standard BIOS call.  See
  481.  *          any technical reference for more info on VIDEO BIOS services.
  482.  */
  483. void scroll_window( int lines, int r1, int c1, int r2, int c2, int attr )
  484. {
  485. char rah, ral;
  486.  
  487.    ASSEMBLE {
  488.         mov     ax, lines
  489.         cmp     ax, 0           /* if line < 0  - scroll window down */
  490.         jge     a1
  491.  
  492.         neg     ax                      /* make lines positive */
  493.         mov     BYTE PTR ral, al        /* save number of lines */
  494.         mov     BYTE PTR rah, 7         /* function 7 -  scroll window down */
  495.         dec     r2                      /* decrement row 2 */
  496.         jmp     SHORT a2
  497.    }
  498. a1:
  499.  
  500.    ASSEMBLE {
  501.         mov     BYTE PTR ral, al        /* number of lines to scroll */
  502.         mov     BYTE PTR rah, 6         /* function 6 - scroll window up */
  503.    }
  504. a2:
  505.  
  506.    ASSEMBLE {
  507.         mov     ax, WORD PTR r1         /* get starting row */
  508.         mov     ch, al                  /* put it in ch */
  509.         mov     ax, WORD PTR c1         /* get starting column */
  510.         mov     cl, al                  /* put it in cl */
  511.         mov     ax, WORD PTR r2         /* get ending row */
  512.         mov     dh, al                  /* put it in dh */
  513.         mov     ax, WORD PTR c2         /* get ending column */
  514.         mov     dl, al                  /* put it in cl */
  515.         mov     ax, WORD PTR attr       /* get attribute */
  516.         mov     bh, al                  /* put it in bh */
  517.         mov     ah, BYTE PTR rah        /* get function number */
  518.         mov     al, BYTE PTR ral        /* get number of lines */
  519.         push    bp                      /* ** in some early BIOS versions ** */
  520.         int     VIDEO_INT               /* ** u must save bp              ** */
  521.         pop     bp
  522.    }
  523. }
  524.  
  525.  
  526. /*
  527.  * Name:    cls
  528.  * Date:    October 5, 1991
  529.  * Notes:   Clear screen using color.
  530.  */
  531. void cls( void )
  532. {
  533.    scroll_window( 0, 0, 0, 24, 79, NORMAL );
  534. }
  535.  
  536.  
  537. /*
  538.  * Name:    show_box
  539.  * Date:    October 5, 1991
  540.  * Passed:  x:     number of lines to scroll
  541.  *          y:     row scroll starts on
  542.  *          p:     column scroll start on
  543.  *          attr:  ending row of scroll
  544.  * Notes:   Easy way to show text on screen.  Based on the display techiniques
  545.  *          in a very good morse code practice program, sorry I don't know
  546.  *          the author's name.  Several morse code pratice programs have been
  547.  *          written, but I am refering to the one written in C and released
  548.  *          around 1984-1986.  Seems like the author was living in California
  549.  *          at that time.
  550.  */
  551. void show_box( int x, int y, struct screen *p, int  attr )
  552. {
  553.  
  554.    while (p->text) {
  555.       s_output( p->text, p->row+y, p->col+x, attr );
  556.       p++;
  557.    }
  558. }
  559.  
  560.  
  561. /*
  562.  * Name:    make_window
  563.  * Date:    October 5, 1991
  564.  * Passed:  col:     upper left column to begin window
  565.  *          row:     upper left row to begin window
  566.  *          width:   number of columns in window
  567.  *          height:  number of rows in window
  568.  *          attr:    color of window border
  569.  * Notes:   Draw the outline of the window then clear all contents.
  570.  *          The begin and ending column have to incremented so when the
  571.  *          window is cleared the borders are not wiped out.
  572.  */
  573. void make_window( int col, int row, int width, int height, int attr )
  574. {
  575.    buf_box( col++, row++, width, height, attr );
  576.    clear_window( col, row, width-2, height-2 );
  577. }
  578.  
  579.  
  580. /*
  581.  * Name:    buf_box
  582.  * Date:    October 5, 1991
  583.  * Passed:  col:     upper left column to begin window
  584.  *          row:     upper left row to begin window
  585.  *          width:   number of columns in window
  586.  *          height:  number of rows in window
  587.  *          attr:    color of window border
  588.  * Notes:   Draw the outline of the window.  See tdecfg.h for the outline
  589.  *          characters.
  590.  */
  591. void buf_box( int col, int row, int width, int height, int attr )
  592. {
  593. int  i;
  594. int  row_count;
  595. char string[82];
  596.  
  597.    if (height > 0 && width > 0 && height < 25 && width < 81) {
  598.       row_count = 1;
  599.       string[0]= U_LEFT;
  600.       for (i=1; i<width-1; i++)
  601.          string[i] = HOR_LINE;
  602.       string[i++] = U_RIGHT; string[i] = '\0';
  603.       s_output( string, row, col, attr );
  604.       ++row_count;
  605.       ++row;
  606.  
  607.       if (row_count < height) {
  608.          string[0] = VER_LINE;
  609.          string[1] = '\0';
  610.          for (i=1; i<height-1; i++) {
  611.             s_output( string, row, col, attr );
  612.             s_output( string, row, col+width-1, attr );
  613.             ++row;
  614.             ++row_count;
  615.          }
  616.       }
  617.  
  618.       if (row_count <= height) {
  619.          string[0] = L_LEFT;
  620.          for (i=1; i<width-1; i++)
  621.             string[i] = HOR_LINE;
  622.          string[i++] = L_RIGHT; string[i] = '\0';
  623.          s_output( string, row, col, attr );
  624.       }
  625.    }
  626. }
  627.  
  628.  
  629. /*
  630.  * Name:    clear_window
  631.  * Date:    October 5, 1991
  632.  * Passed:  col:     upper left column to begin window
  633.  *          row:     upper left row to begin window
  634.  *          width:   number of columns in window
  635.  *          height:  number of rows in window
  636.  * Notes:   Clear the insides of the window.
  637.  */
  638. void clear_window( int col, int row, int width, int height )
  639. {
  640. /*   scroll_window( height, row, col, row+height-1, col+width-1, NORMAL ); */
  641.    scroll_window( 0, row, col, row+height-1, col+width-1, NORMAL );
  642. }
  643.  
  644.  
  645. /*
  646.  * Name:    window_control
  647.  * Date:    October 5, 1991
  648.  * Passed:  window_ptr: pointer to pointer of window (head of window stack)
  649.  *          action:     are SAVEing or RESTOREing the contents of a window
  650.  *          col:        upper left column of window
  651.  *          row:        upper left row of window
  652.  *          width:      number of characters in window
  653.  *          height:     number of rows in window
  654.  * Notes:   Save or restore the contents of the screen under a pop-up or
  655.  *          pull-down window.  Use a stack to store the windows so an unlimited
  656.  *          number of windows may be saved and restored.
  657.  */
  658. void window_control( WINDOW **window_ptr, int action, int col, int row,
  659.                      int width, int height )
  660. {
  661. WINDOW  *p;
  662. size_t  store_me;
  663.  
  664.    if (action == SAVE) {
  665.       p = (WINDOW *)malloc( sizeof(WINDOW) );
  666.       if (p != NULL) {
  667.          p->n = NULL;
  668.  
  669.          /*
  670.           * push a window on the stack
  671.           */
  672.          if (*window_ptr != NULL)
  673.             p->n = *window_ptr;
  674.          *window_ptr = p;
  675.          store_me = (width * height) * sizeof( int );
  676.          p->buf = (int *)malloc( store_me );
  677.          save_window( p->buf, col, row, width, height );
  678.       }
  679.    } else if (action == RESTORE) {
  680.       if (*window_ptr != NULL) {
  681.          p = *window_ptr;
  682.          restore_window( p->buf, col, row, width, height );
  683.  
  684.          /*
  685.           * pop a window off the stack
  686.           */
  687.          *window_ptr = p->n;
  688.          free( p->buf );
  689.          free( p );
  690. }  }  }
  691.  
  692.  
  693. /*
  694.  * Name:    save_window
  695.  * Date:    October 5, 1991
  696.  * Passed:  destination: pointer to store contents of screen
  697.  *          col:         upper left column of window
  698.  *          row:         upper left row of window
  699.  *          width:       number of characters in window
  700.  *          height:      number of rows in window
  701.  * Notes:   Do an optimal save.  Save only the contents of the screen that the
  702.  *          window writes over.  Some algorithms save the entire contents of
  703.  *          the screen - wasteful.
  704.  */
  705. void save_window( int *destination, int col, int row, int width, int height )
  706. {
  707. int i, j, offset;
  708. int far *pointer;
  709.  
  710.    pointer = cfg.videomem;
  711.    offset = row * 80 + col;
  712.    pointer += offset;
  713.    for (i=0; i < height; i++) {
  714.       for (j=0; j < width; j++)
  715.          *destination++ = *(pointer + j);
  716.       pointer += 80;
  717.    }
  718. }
  719.  
  720.  
  721. /*
  722.  * Name:    restore_window
  723.  * Date:    October 5, 1991
  724.  * Passed:  source:      pointer of source of contents of screen
  725.  *          col:         upper left column of window
  726.  *          row:         upper left row of window
  727.  *          width:       number of characters in window
  728.  *          height:      number of rows in window
  729.  * Notes:   Do an optimal restore.  Restore only the contents of the screen
  730.  *          that the window writes over.  Some algorithms restore the entire
  731.  *          contents of the screen - wasteful.
  732.  */
  733. void restore_window( int *source, int col, int row, int width, int height )
  734. {
  735. int i, j, offset;
  736. int far *pointer;
  737.  
  738.    pointer = cfg.videomem;
  739.    offset = row * 80 + col;
  740.    pointer += offset;
  741.    for (i=0; i < height; i++) {
  742.       for (j=0; j < width; j++)
  743.          *(pointer + j) = *source++;
  744.       pointer += 80;
  745.    }
  746. }
  747.